using Digitalmes.Application.Providers;
using Digitalmes.Application.Scada.Models;
using Digitalmes.Domain.Entities.Mes.Integrations;

namespace Digitalmes.Application.Services.Impl;

/// <summary>
/// 数据同步服务。
/// </summary>
internal sealed class RemoteSynchronousService(
    IRepository<IntgrSyncRemote> syncRemoteRepo,
    ISysConfigQueryService sysConfigQueryService,
    IRemoteSynchronousProvider remoteSynchronousProvider) : IRemoteSynchronousService
{
    public async Task PushAsync(OutboundOutput output, CancellationToken cancellationToken = default)
    {
        // 检查是否有推送记录，不能重复推送
        if(await syncRemoteRepo.IsAnyAsync(m => m.StepExecutionId == output.StepExecutionId, cancellationToken))
        {
            return;
        }

        // 推送工艺步骤执行数据，用于在工序出站后实时推送
        var syncMode = await sysConfigQueryService.GetValueAsync(ConfigKeys.SynchronousToRemoteMode);
        if (syncMode == "Mark")
        {
            IntgrSyncRemote dataSync = new()
            {
                Sn = output.Sn,
                StepExecutionId = output.StepExecutionId,
                LineId = output.LineId,
                LineCode = output.LineCode,
                WorkstationId = output.WorkstationId,
                WorkstationCode = output.WorkstationCode,
                OperationId = output.OperationId,
                OperationCode = output.OperationCode,
                Status = RemoteSyncStatusEnum.Ready,
                SyncMode = RemoteSyncModeEnum.Mark,
                CreatedTime = DateTime.Now,
            };
            await syncRemoteRepo.InsertAsync(dataSync, cancellationToken);
        }
        else if (syncMode == "Realtime")
        {
            if (syncMode == "Completed" && !output.IsCompelted)
            {
                return;
            }

            IntgrSyncRemote dataSync = new()
            {
                Sn = output.Sn,
                StepExecutionId = output.StepExecutionId,
                LineId = output.LineId,
                LineCode = output.LineCode,
                WorkstationId = output.WorkstationId,
                WorkstationCode = output.WorkstationCode,
                OperationId = output.OperationId,
                OperationCode = output.OperationCode,
                SyncMode = syncMode == "Completed" ? RemoteSyncModeEnum.Completed : RemoteSyncModeEnum.Realtime,
                CreatedTime = DateTime.Now,
                StartTime = DateTime.Now,
            };

            // 同步数据
            var (ok, err) = await remoteSynchronousProvider.PushAsync(dataSync.StepExecutionId, dataSync.SyncMode, cancellationToken);
            dataSync.EndTime = DateTime.Now;
            dataSync.SyncMethod = remoteSynchronousProvider.SyncMethod;
            dataSync.Status = ok ? RemoteSyncStatusEnum.Completed : RemoteSyncStatusEnum.Failure;
            dataSync.ErrorMessage = err;
            dataSync.SyncCount = 1;

            await syncRemoteRepo.InsertAsync(dataSync, cancellationToken);
        }
    }

    public async Task RetryAsync(long syncRemoteId, CancellationToken cancellationToken = default)
    {
        var dataSync = await syncRemoteRepo.GetByIdAsync(syncRemoteId, cancellationToken);
        // 未成功推送的数据可再次推送
        if (dataSync != null && dataSync.Status is not RemoteSyncStatusEnum.Completed)
        {
            await PushAsync([dataSync], cancellationToken);
        }
    }

    public async Task PushReadyAsync(CancellationToken cancellationToken = default)
    {
        // 推送已出站还未同步的数据，一般用于定时同步
        var dataSyncList = await syncRemoteRepo.GetListAsync(m => m.Status == RemoteSyncStatusEnum.Ready, cancellationToken);
        if (dataSyncList.Count == 0)
        {
            return;
        }

        await PushAsync(dataSyncList, cancellationToken);
    }

    public async Task PushFailureAsync(CancellationToken cancellationToken = default)
    {
        // 推送同步失败的数据，一般用于定时同步
        var dataSyncList = await syncRemoteRepo.GetListAsync(m => m.Status == RemoteSyncStatusEnum.Failure, cancellationToken);
        if (dataSyncList.Count == 0)
        {
            return;
        }

        await PushAsync(dataSyncList, cancellationToken);
    }

    private async Task PushAsync(IEnumerable<IntgrSyncRemote> dataSyncList, CancellationToken cancellationToken = default)
    {
        // 找到工艺步骤数据和过程数据集合
        // 按接口组合好后推送
        foreach (var item in dataSyncList)
        {
            item.StartTime = DateTime.Now;

            // 同步数据
            var (ok, err) = await remoteSynchronousProvider.PushAsync(item.StepExecutionId, item.SyncMode, cancellationToken);

            item.EndTime = DateTime.Now;
            item.SyncMethod = remoteSynchronousProvider.SyncMethod;
            item.Status = ok ? RemoteSyncStatusEnum.Completed : RemoteSyncStatusEnum.Failure;
            item.ErrorMessage = err;
            item.SyncCount = item.SyncCount + 1;
            await syncRemoteRepo.UpdateAsync(item, m => new
            {
                m.StartTime,
                m.EndTime,
                m.SyncMethod,
                m.Status,
                m.ErrorMessage,
                m.SyncCount,
            }, cancellationToken);
        }
    }
}
